package com.ajocer.springbootinit.rag;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 提示词模板管理服务
 * 负责加载和管理提示词模板，支持模板变量替换和版本管理
 */
@Service
@Slf4j
public class PromptTemplateManager {

    private final ResourceLoader resourceLoader;
    private final String promptTemplatePath;
    private static final Pattern VARIABLE_PATTERN = Pattern.compile("\\{\\{(.*?)\\}\\}");
    
    @Autowired
    private PromptCompressor promptCompressor;

    public PromptTemplateManager(ResourceLoader resourceLoader, 
                                @Value("${tourism.rag.prompt-template-path}") String promptTemplatePath) {
        this.resourceLoader = resourceLoader;
        this.promptTemplatePath = promptTemplatePath;
    }

    /**
     * 根据模板名称和版本加载提示词模板
     * @param templateName 模板名称
     * @param version 模板版本，如果为null，则使用最新版本
     * @return 提示词模板内容
     */
    @Cacheable(value = "promptTemplates", key = "#templateName + '-' + #version")
    public String loadTemplate(String templateName, String version) {
        String templatePath = buildTemplatePath(templateName, version);
        try {
            Resource resource = resourceLoader.getResource(templatePath);
            return asString(resource);
        } catch (IOException e) {
            log.error("Failed to load prompt template: {}", templatePath, e);
            throw new RuntimeException("Failed to load prompt template: " + templatePath, e);
        }
    }

    /**
     * 使用变量填充提示词模板
     * @param template 提示词模板
     * @param variables 变量映射
     * @return 填充后的提示词
     */
    public String fillTemplate(String template, Map<String, Object> variables) {
        if (variables == null || variables.isEmpty()) {
            return template;
        }

        StringBuffer result = new StringBuffer();
        Matcher matcher = VARIABLE_PATTERN.matcher(template);

        while (matcher.find()) {
            String variableName = matcher.group(1).trim();
            Object value = variables.get(variableName);
            String replacement = value != null ? value.toString() : "";
            matcher.appendReplacement(result, Matcher.quoteReplacement(replacement));
        }
        matcher.appendTail(result);

        // 使用提示词压缩技术优化提示词
        return promptCompressor.compress(result.toString());
    }

    /**
     * 使用变量填充提示词模板
     * @param templateName 模板名称
     * @param version 模板版本
     * @param variables 变量映射
     * @return 填充后的提示词
     */
    public String fillTemplate(String templateName, String version, Map<String, Object> variables) {
        String template = loadTemplate(templateName, version);
        return fillTemplate(template, variables);
    }

    /**
     * 构建提示词模板路径
     */
    private String buildTemplatePath(String templateName, String version) {
        if (version == null || version.isEmpty()) {
            return promptTemplatePath + templateName + ".txt";
        } else {
            return promptTemplatePath + templateName + "_v" + version + ".txt";
        }
    }

    /**
     * 将资源转换为字符串
     */
    private String asString(Resource resource) throws IOException {
        try (Reader reader = new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8)) {
            return FileCopyUtils.copyToString(reader);
        }
    }
    
    /**
     * 创建变量映射构建器
     */
    public VariablesBuilder variables() {
        return new VariablesBuilder();
    }
    
    /**
     * 变量映射构建器
     */
    public static class VariablesBuilder {
        private final Map<String, Object> variables = new HashMap<>();
        
        public VariablesBuilder with(String name, Object value) {
            variables.put(name, value);
            return this;
        }
        
        public Map<String, Object> build() {
            return variables;
        }
    }
} 